Skip to content

feat(endpoint): reject alias property on unsupported record types#6188

Merged
k8s-ci-robot merged 7 commits intokubernetes-sigs:masterfrom
u-kai:feat/add-alias-validation
Feb 28, 2026
Merged

feat(endpoint): reject alias property on unsupported record types#6188
k8s-ci-robot merged 7 commits intokubernetes-sigs:masterfrom
u-kai:feat/add-alias-validation

Conversation

@u-kai
Copy link
Copy Markdown
Member

@u-kai u-kai commented Feb 11, 2026

What does it do ?

This PR adds validation logic to CheckEndpoint to ensure that alias=true is only allowed for supported record types.

Endpoints with unsupported combinations (e.g., MX + alias=true) are now rejected during validation instead of being handled silently in providers.

Motivation

Currently, invalid alias configurations can pass through the pipeline and be handled (or silently fixed) inside specific providers, which leads to inconsistent behavior and makes user mistakes harder to detect.

Related issues: #6017

More

  • Yes, this PR title follows Conventional Commits
  • Yes, I added unit tests
  • Yes, I updated end user documentation accordingly

Signed-off-by: u-kai <76635578+u-kai@users.noreply.github.com>
@k8s-ci-robot k8s-ci-robot added cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Feb 11, 2026
@coveralls
Copy link
Copy Markdown

coveralls commented Feb 11, 2026

Pull Request Test Coverage Report for Build 22183896879

Warning: This coverage report may be inaccurate.

This pull request's base commit is no longer the HEAD commit of its target branch. This means it includes changes from outside the original pull request, including, potentially, unrelated coverage changes.

Details

  • 0 of 0 changed or added relevant lines in 0 files are covered.
  • 20 unchanged lines in 1 file lost coverage.
  • Overall coverage increased (+0.01%) to 79.169%

Files with Coverage Reduction New Missed Lines %
endpoint.go 20 86.27%
Totals Coverage Status
Change from base Build 21559764040: 0.01%
Covered Lines: 16050
Relevant Lines: 20273

💛 - Coveralls

Copy link
Copy Markdown
Member

@ivankatliarchuk ivankatliarchuk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add tests here as well

if ok := ep.CheckEndpoint(); !ok {

So it's clear where the validation applies?

Comment thread endpoint/endpoint.go Outdated
// TODO: rename to Validate
// CheckEndpoint Check if endpoint is properly formatted according to RFC standards
func (e *Endpoint) CheckEndpoint() bool {
if !e.supportAlias() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if !e.supportAlias() {
if !e.supportsAlias {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've fixed it.

Comment thread endpoint/endpoint.go Outdated
// CheckEndpoint Check if endpoint is properly formatted according to RFC standards
func (e *Endpoint) CheckEndpoint() bool {
if !e.supportAlias() {
if _, ok := e.GetBoolProviderSpecificProperty("alias"); ok {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have constant with TODO comment to review source/annotations package, as we have annotations defined in location that cause circular dependencies.

Comment thread endpoint/endpoint.go Outdated
func (e *Endpoint) CheckEndpoint() bool {
if !e.supportAlias() {
if _, ok := e.GetBoolProviderSpecificProperty("alias"); ok {
log.Debugf("Endpoint %s of type %s does not support alias records in ExternalDNS", e.DNSName, e.RecordType)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ExternalDNS not required

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a warning. Basically this is a misconfiguration on client side

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this log in unit tests?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've fixed the log message and added unit tests.

Comment thread endpoint/endpoint_test.go
Targets: Targets{"10 5 5060 sip.example.com."},
ProviderSpecific: ProviderSpecific{{Name: "alias", Value: "true"}},
},
expected: false,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

false is default

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you clarify what you mean by "false is default"?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You do not need explicit false, as its a default value

Comment thread endpoint/endpoint.go Outdated
func (e *Endpoint) CheckEndpoint() bool {
if !e.supportAlias() {
if _, ok := e.GetBoolProviderSpecificProperty("alias"); ok {
log.Debugf("Endpoint %s of type %s does not support alias records in ExternalDNS", e.DNSName, e.RecordType)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this log in unit tests?

…alias constant

Signed-off-by: u-kai <76635578+u-kai@users.noreply.github.com>
Signed-off-by: u-kai <76635578+u-kai@users.noreply.github.com>
Signed-off-by: u-kai <76635578+u-kai@users.noreply.github.com>
@ivankatliarchuk
Copy link
Copy Markdown
Member

/approve

@k8s-ci-robot k8s-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Feb 15, 2026
@ivankatliarchuk
Copy link
Copy Markdown
Member

/approve cancel

@k8s-ci-robot k8s-ci-robot removed the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Feb 15, 2026
Comment thread endpoint/endpoint.go

// TODO: review source/annotations package to consolidate alias key definitions;
// currently duplicated here to avoid circular dependency.
const providerSpecificAlias = "alias"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

most likely too long, but not an issue. You not using this constant in tests

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've fixed it.

@ivankatliarchuk
Copy link
Copy Markdown
Member

User documentation is missing. Worth to find out the right location for this

Signed-off-by: u-kai <76635578+u-kai@users.noreply.github.com>
…NAME

Signed-off-by: u-kai <76635578+u-kai@users.noreply.github.com>
@ivankatliarchuk
Copy link
Copy Markdown
Member

I could not find example of testing this feature end-2-end. Could you share it pls?

Comment thread endpoint/endpoint_test.go

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
logger, hook := test.NewNullLogger()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make sure to use shared construct. let's not create for every test a solution

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, it’s difficult to use a shared construct due to circular dependencies.
Once this PR is merged, I was planning to refactor the structure and introduce a shared construct in a follow-up PR.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok

@u-kai
Copy link
Copy Markdown
Member Author

u-kai commented Feb 22, 2026

Yes. I verified this behavior end-to-end using the DNSEndpoint CRD.

I was able to successfully create a normal MX record using the following manifest:

apiVersion: externaldns.k8s.io/v1alpha1
kind: DNSEndpoint
metadata:
  name: alias
  namespace: default
spec:
  endpoints:
    - dnsName: test.mail.example.com
      recordType: MX
      recordTTL: 600
      targets:
        - "10 mail.example.com"

However, when I added the alias providerSpecific property as shown below:

apiVersion: externaldns.k8s.io/v1alpha1
kind: DNSEndpoint
metadata:
  name: alias
  namespace: default
spec:
  endpoints:
    - dnsName: test.mail.example.com
      recordType: MX
      recordTTL: 600
      targets:
        - "10 mail.example.com"
      providerSpecific:
        - name: "alias"
          value: "true"

ExternalDNS produced the following warnings and skipped the endpoint:

WARN Endpoint test.mail.example.com of type MX does not support alias records
WARN Skipping endpoint [:test.mail.example.com] due to invalid configuration [MX:10 mail.example.com]

This confirms that MX records with alias=true are rejected and not processed, which is the behavior this PR is addressing.

@ivankatliarchuk
Copy link
Copy Markdown
Member

/approve

@k8s-ci-robot k8s-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Feb 22, 2026
@ivankatliarchuk
Copy link
Copy Markdown
Member

I was testing something. And found this log

DEBU[0000] Modifying endpoint: alias.example.com 600 IN CNAME  multi.example.com [], setting alias=false

We don't have any aliases set

apiVersion: externaldns.k8s.io/v1alpha1
kind: DNSEndpoint
metadata:
  name: multi-record-types
  namespace: default
spec:
  endpoints:
    - dnsName: multi.example.com
      recordTTL: 300
      recordType: A
      targets:
        - 172.16.0.1
    - dnsName: multi.example.com
      recordTTL: 300
      recordType: AAAA
      targets:
        - "2001:db8::2"
    - dnsName: alias.example.com
      recordTTL: 600
      recordType: CNAME
      targets:
        - multi.example.com

@ivankatliarchuk
Copy link
Copy Markdown
Member

needs clarification. as was not there before

/remove-approve

@k8s-ci-robot k8s-ci-robot removed the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Feb 23, 2026
@u-kai
Copy link
Copy Markdown
Member Author

u-kai commented Feb 23, 2026

This behavior is not introduced by this PR and already exists in the current master branch.

To verify, I switched to the latest master branch and applied the same DNSEndpoint configuration (with domain names adjusted to my domain). The following log was produced:

DEBU[0021] Modifying endpoint: alias.example.com 600 IN CNAME multi.example.com [], setting alias=false

@ivankatliarchuk
Copy link
Copy Markdown
Member

The logic most likely had changed in this PR https://github.com/kubernetes-sigs/external-dns/pull/6021/changes

I'll try to understand it better over a weekend.

@ivankatliarchuk
Copy link
Copy Markdown
Member

Tested against https://github.com/kubernetes-sigs/external-dns/tree/v0.20.0. The message

DEBU[0021] Modifying endpoint: alias

Is there as well

/approve

@k8s-ci-robot
Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: ivankatliarchuk

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. approved Indicates a PR has been approved by an approver from all required OWNERS files. labels Feb 26, 2026
@k8s-ci-robot k8s-ci-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Feb 28, 2026
@ivankatliarchuk
Copy link
Copy Markdown
Member

/lgtm

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Feb 28, 2026
@k8s-ci-robot k8s-ci-robot merged commit a4e1679 into kubernetes-sigs:master Feb 28, 2026
17 checks passed
ivankatliarchuk added a commit to gofogo/k8s-sigs-external-dns-fork that referenced this pull request Mar 10, 2026
…_total

* master: (21 commits)
  refactor(testutils): extract log test helpers into subpackage to fix (kubernetes-sigs#6236)
  chore(deps): bump mkdocs-material (kubernetes-sigs#6237)
  feat(endpoint): reject alias property on unsupported record types (kubernetes-sigs#6188)
  fix(charts): Skip cluster-scope RBAC on namespaced (kubernetes-sigs#5843)
  chore(deps): bump the dev-dependencies group across 1 directory with 3 updates (kubernetes-sigs#6226)
  feat(pdns): add --[no-]prefer-alias flag and alias annotation support (kubernetes-sigs#6129)
  fix(ci): failed to download the coveralls binary from GitHub releases (kubernetes-sigs#6228)
  docs: add external-dns-pscloud-webhook to New providers list (kubernetes-sigs#6214)
  fix(crd): allow trailing dot in CNAME targets (kubernetes-sigs#6218)
  docs: added deep wiki badge (kubernetes-sigs#6215)
  feat(crd): Support MX record with trailing dot (kubernetes-sigs#6163)
  chore(source): standardize sources with merge endpionts and deduplicate targets (kubernetes-sigs#6174)
  chore(store): Added RESTConfig() to ClientGenerator (kubernetes-sigs#6177)
  chore(ingress): clarify that both IP and Hostname are collected from LoadBalancer status (kubernetes-sigs#6138)
  chore(endpoint): added empty checks (kubernetes-sigs#6157)
  chore(linter): enable unparam (kubernetes-sigs#6160)
  fix(tlsutils): fix nil error wrapping and wrong env var in TLS config (kubernetes-sigs#6198)
  chore(endpoint): harden crypto (kubernetes-sigs#6197)
  feat(fqdn): Deduplicate and sort ExecTemplate output. Add functions (kubernetes-sigs#6173)
  benchmark(endpoint): endpoint benchmarks (kubernetes-sigs#6156)
  ...
ivankatliarchuk added a commit to gofogo/k8s-sigs-external-dns-fork that referenced this pull request Mar 10, 2026
* master: (23 commits)
  refactor(testutils): extract log test helpers into subpackage to fix (kubernetes-sigs#6236)
  chore(deps): bump mkdocs-material (kubernetes-sigs#6237)
  feat(endpoint): reject alias property on unsupported record types (kubernetes-sigs#6188)
  fix(charts): Skip cluster-scope RBAC on namespaced (kubernetes-sigs#5843)
  chore(deps): bump the dev-dependencies group across 1 directory with 3 updates (kubernetes-sigs#6226)
  feat(pdns): add --[no-]prefer-alias flag and alias annotation support (kubernetes-sigs#6129)
  fix(ci): failed to download the coveralls binary from GitHub releases (kubernetes-sigs#6228)
  docs: add external-dns-pscloud-webhook to New providers list (kubernetes-sigs#6214)
  fix(crd): allow trailing dot in CNAME targets (kubernetes-sigs#6218)
  docs: added deep wiki badge (kubernetes-sigs#6215)
  feat(crd): Support MX record with trailing dot (kubernetes-sigs#6163)
  chore(source): standardize sources with merge endpionts and deduplicate targets (kubernetes-sigs#6174)
  chore(store): Added RESTConfig() to ClientGenerator (kubernetes-sigs#6177)
  chore(ingress): clarify that both IP and Hostname are collected from LoadBalancer status (kubernetes-sigs#6138)
  chore(endpoint): added empty checks (kubernetes-sigs#6157)
  chore(linter): enable unparam (kubernetes-sigs#6160)
  fix(tlsutils): fix nil error wrapping and wrong env var in TLS config (kubernetes-sigs#6198)
  chore(endpoint): harden crypto (kubernetes-sigs#6197)
  feat(fqdn): Deduplicate and sort ExecTemplate output. Add functions (kubernetes-sigs#6173)
  benchmark(endpoint): endpoint benchmarks (kubernetes-sigs#6156)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. docs lgtm "Looks good to me", indicates that a PR is ready to be merged. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. source

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants